package com.bee.app.util;

import java.security.SecureRandom;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

/**
 * 用户密码加密与验证
 * 
 * @author liuzy
 * @version 1.0
 * @since 2015年6月30日
 */
public class PwdUtil {
	public static void main(String[] args) {
		String password = "111111";
		System.out.println("pwd:" + password);
		String salt = getSalt();
		System.out.println("salt:" + salt);
		String pwd = encrypt(password, salt);
		System.out.println("encrypt:" + pwd);
		System.out.println("length:" + pwd.length());
		System.out.println("validate:" + validate(password, salt, pwd));
	}

	public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
	public static final int SALT_BYTE_SIZE = 24;
	public static final int HASH_BYTE_SIZE = 24;
	public static final int PBKDF2_ITERATIONS = 1000;
	public static final int ITERATION_INDEX = 0;
	public static final int SALT_INDEX = 1;
	public static final int PBKDF2_INDEX = 2;

	/**
	 * 生成盐
	 * 
	 * @return
	 */
	public static String getSalt() {
		SecureRandom random = new SecureRandom();
		byte[] salt = new byte[SALT_BYTE_SIZE];
		random.nextBytes(salt);
		return StringKit.toHex(salt);
	}

	/**
	 * PBKDF2加密
	 * 
	 * @param salt
	 * @param password
	 * @return
	 */
	public static String encrypt(String password, String salt) {
		try {
			byte[] hash = pbkdf2(password.toCharArray(), StringKit.fromHex(salt), PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
			return StringKit.toHex(hash);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 慢HASH法，验证密码
	 * 
	 * @param salt
	 * @param password
	 * @param pwd
	 * @return
	 */
	public static boolean validate(String password, String salt, String pwd) {
		byte[] a = pbkdf2(password.toCharArray(), StringKit.fromHex(salt), PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
		byte[] b = StringKit.fromHex(pwd);
		int diff = a.length ^ b.length;
		for (int i = 0; i < a.length && i < b.length; i++)
			diff |= a[i] ^ b[i];
		return diff == 0;
	}

	/**
	 * PBKDF2加密
	 * 
	 * @param password
	 * @param salt
	 * @param iterations
	 * @param bytes
	 * @return
	 */
	private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int bytes) {
		try {
			PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, bytes * 8);
			SecretKeyFactory skf = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
			return skf.generateSecret(spec).getEncoded();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

}
